package util

import (
	"bytes"
	"reflect"
	"strings"
	"unicode"
)

// ParseTag 解析标签
func ParseTag(tagText string) (tagAttrMap map[string]string) {
	if tagText == "" {
		return tagAttrMap
	}
	tagAttrMap = make(map[string]string, 2)
	// 切割属性
	tagAttrs := strings.Split(tagText, ";")
	for i := range tagAttrs {
		// 根据 冒号 分割
		tagAttrKv := strings.Split(tagAttrs[i], ":")
		if len(tagAttrKv) > 1 {
			tagAttrMap[tagAttrKv[0]] = tagAttrKv[1]
		} else {
			tagAttrMap[tagAttrKv[0]] = tagAttrKv[0]
		}
	}
	return
}

// ReflectLookupField 反射查找字段
func ReflectLookupField(obj any, call func(name string, getTag func(key string) string, index []int) bool) bool {
	obj = reflectNew(obj)
	value := reflect.ValueOf(obj).Elem()
	// 记录索引
	for i := 0; i < value.NumField(); i++ {
		fv := value.Field(i)
		value.Type().Kind()
		ft := value.Type().Field(i)
		if readFieldToKV(&fv, &ft, call, make([]int, 0)) {
			return true
		}
	}
	return false
}

// readFieldToKV 递归反射遍历结构体的字段信息
func readFieldToKV(fv *reflect.Value, ft *reflect.StructField,
	call func(name string, getTag func(key string) string, index []int) bool, index []int) bool {
	// 保存索引
	index = append(index, ft.Index...)
	if ft.Anonymous && (fv.Kind() == reflect.Struct || (fv.Kind() == reflect.Struct && fv.Elem().Kind() == reflect.Struct)) {
		var numField int
		if fv.Kind() == reflect.Struct {
			numField = fv.NumField()
		} else {
			numField = fv.Elem().NumField()
		}
		for i := 0; i < numField; i++ {
			ffv := fv.Field(i)
			fft := ft.Type.Field(i)
			if readFieldToKV(&ffv, &fft, call, index) {
				return true
			}
		}
		return false
	}
	if !fv.CanInterface() {
		return false
	}
	// ...... 循环中的主逻辑
	return call(ft.Name, ft.Tag.Get, index)
}

// CamelToSnakeCase 将驼峰命名转换为下划线命名
func CamelToSnakeCase(s string) string {
	var buffer bytes.Buffer
	for i, r := range s {
		if unicode.IsUpper(r) {
			if i > 0 {
				buffer.WriteRune('_')
			}
			buffer.WriteRune(unicode.ToLower(r))
		} else {
			buffer.WriteRune(r)
		}
	}
	return buffer.String()
}

// IsEmpty 判断字段是否为空
func IsEmpty(object any) bool {
	if object == nil {
		return true
	}
	fieldType := reflect.TypeOf(object)
	switch fieldType.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return reflect.ValueOf(object).Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return reflect.ValueOf(object).Uint() == 0
	case reflect.String:
		return reflect.ValueOf(object).String() == ""
	case reflect.Float32, reflect.Float64:
		return reflect.ValueOf(object).Float() == 0
	case reflect.Struct:
		return reflect.DeepEqual(object, reflect.New(fieldType).Elem().Interface())
	default:
		return false
	}
}

// GetFieldValue 获取字段值
func GetFieldValue(object any, index []int) any {
	val := reflect.ValueOf(object)
	if reflect.TypeOf(object).Kind() == reflect.Pointer {
		val = val.Elem()
	}
	return val.FieldByIndex(index).Interface()
}

// SetFieldValue 设置字段值
func SetFieldValue(object any, val any, index []int) {
	if reflect.TypeOf(object).Kind() != reflect.Pointer {
		return
	}
	field := reflect.ValueOf(object).Elem().FieldByIndex(index)
	field.Set(reflect.ValueOf(val).Convert(field.Type()))
}

// GetFieldIntValue 获取字段值
func GetFieldIntValue(object any, index []int) int64 {
	val := reflect.ValueOf(object)
	if reflect.TypeOf(object).Kind() == reflect.Pointer {
		val = val.Elem()
	}
	val = val.FieldByIndex(index)
	switch val.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
		reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return val.Int()
	default:
		return 0
	}
}

func reflectNew(target interface{}) interface{} {
	if target == nil {
		return nil
	}
	t := reflect.TypeOf(target)
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	newStruc := reflect.New(t)
	return newStruc.Interface()
}
